package com.raos.example.listener;

import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.read.listener.ReadListener;
import com.mybatisflex.spring.service.impl.ServiceImpl;
import com.raos.example.dao.EmployeeDao;
import com.raos.example.model.EmployeeEntity;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * 员工信息导入监听处理类
 *
 * @author raos
 * @email 991207823@qq.com
 * @date 2023-08-26 10:27
 */
@Slf4j
@Component
public class EmployeeListener extends ServiceImpl<EmployeeDao, EmployeeEntity> implements ReadListener<EmployeeEntity> {

    private static final int batchSize = 10000;
    private List<EmployeeEntity> employeeList = new ArrayList<>();
    // 线程池
    private ExecutorService executorService = Executors.newFixedThreadPool(20);
    private ThreadLocal<ArrayList<EmployeeEntity>> employeeList2 = ThreadLocal.withInitial(ArrayList::new);
    private static AtomicInteger count = new AtomicInteger(1);

    @Resource
    private EmployeeListener listener;

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void invoke(EmployeeEntity data, AnalysisContext context) {
        data.setEmployeeId(null); // 使用数据库自增主键
        // 单线程逐条解析，单线程单条插入
        // saveOne(data);
        // 单线程逐条解析，单线程批量插入
        /*employeeList.add(data);
        if (employeeList.size() >= batchSize) {
            saveData();
        }*/
        // 多线程解析，单线程批量插入
        employeeList2.get().add(data);
        if (employeeList2.get().size() >= batchSize) {
//            saveData2();
            // 多线程解析，多线程线程批量插入
            asyncSaveData();
        }
    }

    public void saveOne(EmployeeEntity data){
        save(data);
        log.info("第" + count.getAndAdd(1) + "次插入1条数据");
    }

    public void saveData() {
        if (!employeeList.isEmpty()) {
            saveBatch(employeeList, employeeList.size());
            log.info("第" + count.getAndAdd(1) + "次插入" + employeeList.size() + "条数据");
            employeeList.clear();
        }
    }

    public void saveData2() {
        if (!employeeList2.get().isEmpty()) {
            saveBatch(employeeList2.get(), employeeList2.get().size());
            log.info("第" + count.getAndAdd(1) + "次插入" + employeeList2.get().size() + "条数据");
            employeeList2.get().clear();
        }
    }

    public void asyncSaveData() {
        if (!employeeList2.get().isEmpty()) {
            ArrayList<EmployeeEntity> employeeDOS = (ArrayList<EmployeeEntity>) employeeList2.get().clone();
            executorService.execute(new SaveTask(employeeDOS, listener));
            employeeList2.get().clear();
        }
    }

    static class SaveTask implements Runnable {

        private List<EmployeeEntity> employeeList;
        private EmployeeListener listener;

        public SaveTask(List<EmployeeEntity> employeeList, EmployeeListener listener) {
            this.employeeList = employeeList;
            this.listener = listener;
        }

        @Override
        public void run() {
            listener.saveBatch(employeeList);
            log.info("第" + count.getAndAdd(1) + "次插入" + employeeList.size() + "条数据");
        }
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void doAfterAllAnalysed(AnalysisContext context) {
        log.info("一个Sheet全部处理完");
        // 多线程解析，单线程批量插入
        /*if (employeeList2.get().size() >= batchSize) {
            saveData2();
        }*/
        // 多线程解析，多线程批量插入
        if (employeeList2.get().size() >= batchSize) {
            asyncSaveData();
        }
    }

}
